import re

from django.contrib.auth.hashers import make_password
from django.db.models.signals import pre_save
from django.dispatch import receiver
from rest_framework import viewsets

from settings.dev import AUTHENTICATION_MODE, MODE_VERIFICATION_CODE
from utils.common_response import APIResponse
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
from rest_framework.exceptions import APIException
from .serializer import LoginUserSerializer, LoginUserSMSSerializer, UserRegisterSerializer, UserSmsRegisterSerializer, \
    LoginSerializer, RegisterSerializer, ForgetPwdSerializer, TeamSerializer
from libs.send_jd_sms import get_code, send_sms_by_mobile
from django.core.cache import cache
# from celery_task.user_task import send_sms
from rest_framework.mixins import CreateModelMixin, ListModelMixin
from .models import User, Team
from libs.send_jd_sms.send_msg import GetCode
from utils.common_logger import logger
from .authentication import LoginAuthentication


# @receiver(pre_save, sender=User)
# def hash_password(sender, instance, **kwargs):
#     if not instance.pk:  # 如果是新建用户
#         instance.password = make_password(instance.password)


class LoginView(ViewSet):
    authentication_classes = []  # 局部禁用
    permission_classes = []
    throttle_classes = []

    @action(methods=['POST'], detail=False)
    def login(self, request):
        print(request.data)
        user_info = LoginSerializer(data=request.data)
        user_info.is_valid(raise_exception=True)
        user = user_info.context.get('user_info')
        token = user_info.context.get('token')
        # user_type = user_info.context.get('user_type')
        # gender = user_info.context.get('gender')
        # mobile = user_info.context.get('mobile')
        return APIResponse(msg='登录成功',
                           user_info=user,
                           token=token)


class RegisterView(ViewSet):
    authentication_classes = []  # 局部禁用
    permission_classes = []
    throttle_classes = []

    @action(methods=['GET'], detail=False)
    def get_mobile(self, request):
        try:
            phone = request.query_params.get('phone')
            if phone == None:
                return APIResponse(code=102, msg='不能为空')
            User.objects.get(phone=phone)
            return APIResponse(code=101, msg='手机号已经存在')
        except:
            return APIResponse(code=100, msg='手机号验证通过')

    @action(methods=['POST'], detail=False)
    def register(self, request):
        print('第一步', request.data)
        ser = RegisterSerializer(data=request.data)
        ser.is_valid(raise_exception=True)
        # 触发序列化类create方法
        ser.save()
        username = ser.context.get('username')
        return APIResponse(msg=f'账号:{username}注册已提交,等待管理员激活')


class SendView(ViewSet):
    # 继承ApiView 自动生成路由
    ###############测试京东云云发送短信接口##########
    @action(methods=['GET'], detail=False)
    def send_sms(self, request, *args, **kwargs):
        # 前端需要把要发送的手机号传入 在地址栏中
        mobile = request.query_params.get('mobile', None)
        code = GetCode.send_sms_by_mobile(mobile)  # 把code存起来，放到缓存中
        cache.set('send_sms_code_%s' % mobile, code)
        # 从缓存中区
        # cache.get('send_sms_code_%s'%mobile)
        if mobile and GetCode.send_sms_by_mobile(mobile):
            return APIResponse(msg='发送成功')
        raise APIException('发送短信出错')

    @action(methods=['POST'], detail=False)
    def chance_pwd(self, request):
        user = request.data.get('user')
        password = request.data.get('password')
        confirm_pwd = request.data.get('confirm_pwd')
        if password == confirm_pwd:
            try:
                user = User.objects.all().filter(username=user).first()
                print(user)
                user.set_password(password)
                user.save()
                return APIResponse(msg='密码修改成功啦！！')
            except Exception as e:
                raise APIException('user not find')

        else:
            return APIResponse(code=101, mag='两次密码不一样！！！')

    @action(methods=['POST'], detail=False)
    def check_code(self, request):
        print(request.data)
        ser = ForgetPwdSerializer(data=request.data)
        if ser.is_valid():
            user = ser.context.get('user')
            return APIResponse(code=100,
                               msg='验证通过了',
                               user=user)
        else:
            raise APIException('再试一次吧！')

    @action(methods=['POST'], detail=False)
    def check_mobile(self, request):
        mobile = request.data.get('mobile')
        if not re.match(r'^1[3-9][0-9]{9}$', str(mobile)):
            raise APIException('手机号码格式不正确')
        user = User.objects.all().filter(phone=mobile).first()
        if not user:
            raise APIException('你没有注册该手机号')
        logger.error('%s手机号码验证通过' % mobile)
        return APIResponse(msg='手机号验证通过!')

    @action(methods=['POST'], detail=False)
    def code_cache(self, request):
        mobile = request.data.get('mobile')
        if not re.match(r'^1[3-9][0-9]{9}$', str(mobile)):
            raise APIException('手机号码格式不正确！！')
        if AUTHENTICATION_MODE == 'debug':
            code = MODE_VERIFICATION_CODE
        else:
            code = GetCode.send_sms_by_mobile(mobile)
        if not code:
            raise APIException('验证码获取失败！！！')
        cache.set('set_code_%s' % mobile, code)
        logger.error('%s的验证码%s已经存入缓存中!!!!' % (mobile, code))
        return APIResponse(code=100, msg='验证码已经存入缓存中！！！')


class UserView(GenericViewSet, CreateModelMixin, ListModelMixin):
    serializer_class = LoginUserSerializer
    queryset = User.objects.all()

    # ********************************手机号码验证和发送验证码

    # 验证手机号是否存在接口---》get请求---》跟数据库有关系，但不需要序列化----》自动生成路由
    @action(methods=['GET'], detail=False)
    def check_mobile(self, request, *args, **kwargs):
        mobile = request.query_params.get('mobile', None)
        if mobile:
            user = User.objects.filter(mobile=mobile).first()
            if user:
                return APIResponse(msg='手机号存在')
        raise APIException('手机号不存在')

    # 发送短信
    @action(methods=['GET'], detail=False)
    def send_sms(self, request, *args, **kwargs):
        # 前端需要把要发送的手机号传入在地址栏中
        mobile = request.query_params.get('mobile', None)
        code = get_code()  # 把code存起来，放在缓存中
        cache.set('send_sms_code_%s' % mobile, code)
        # 从缓存中取
        # cache.get('send_sms_code_%s' % mobile)

        if mobile:
            # 开启一个线程，执行发送短信
            # t = Thread(target=send_sms_by_mobile, args=[mobile, code])
            # t.start()
            # 提交异步任务---》异步发送
            res = send_sms.delay(mobile, code)
            print(res)
            return APIResponse(msg='短信已经发送')
        raise APIException('手机号没有携带！')

    # ******************************************登录功能***************************
    # 判断登录方式用哪个序列化类
    def get_serializer_class(self):
        if self.action == 'sms_login':
            return LoginUserSMSSerializer
        elif self.action == 'register' or self.action == 'create':
            return UserRegisterSerializer
        elif self.action == 'sms_register':
            return UserSmsRegisterSerializer
        else:
            # return super().get_serializer_class()
            return self.serializer_class

    # 多方式登录接口---->要不要序列化类----->要序列化类----->继承的视图类基类
    # post请求 ------->前端携带的数据
    @action(methods=['POST'], detail=False)
    def mul_login(self, request, *args, **kwargs):
        # # 校验逻辑要写在序列化类中
        # ser = self.get_serializer(data=request.data)
        # # 只要执行它，就会执行字段自己的校验规则，局部钩子，全局钩子，全局钩子（全局钩子中写验证逻辑，生成token的逻辑）
        # ser.is_valid(raise_exception=True)  # 如果校验失败，异常会抛出
        # username = ser.context.get('username')
        # token = ser.context.get('token')
        # icon = ser.context.get('icon')
        # return APIResponse(username=username,token=token,icon=icon)
        return self._common_login(request, *args, **kwargs)

    @action(methods=['POST'], detail=False)
    def sms_login(self, request, *args, **kwargs):
        # 前端传入的格式 {mobile:11111,code:8888}
        # 逻辑在序列化类里面
        return self._common_login(request, *args, **kwargs)

    # 两个登录方式的公共部分
    def _common_login(self, request, *args, **kwargs):
        # 校验逻辑要写在序列化类中
        ser = self.get_serializer(data=request.data)
        # 只要执行它，就会执行字段自己的校验规则，局部钩子，全局钩子，全局钩子（全局钩子中写验证逻辑，生成token的逻辑）
        ser.is_valid(raise_exception=True)  # 如果校验失败，异常会抛出
        username = ser.context.get('username')
        token = ser.context.get('token')
        icon = ser.context.get('icon')
        return APIResponse(username=username, token=token, icon=icon)

    # ************************************注册功能***************************

    # 方式一
    # 自己写的 访问 127.0.0.1：8000/api/v1/user/userinfo/register/   --->post请求即可
    @action(methods=['POST'], detail=False)
    def register(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        # super().create(request,*args,**kwargs)  # 只要这样写，又会走序列化类
        return APIResponse(mag='注册成功')

    def list(self, request, *args, **kwargs):
        print(request.query_params['name'])
        super().list(request, *args, **kwargs)
        return APIResponse(msg='111')

    @action(methods=['GET'], detail=True)
    def send_sms(self, request, pk):
        print(pk)
        # 手机号，从哪去，假设get请求，携带了参数
        phone = request.query_params.get('phone')
        print('发送成功,%s' % phone)
        return Response({'code': 100, 'msg': '发送成功'})

    # 方式二
    # 不自己写了,只要继承CreateModelMixin，访问：127.0.0.1：8000/api/v1/user/userinfo   --->post请求即可
    # 只要post请求过来就会执行create
    def create(self, request, *args, **kwargs):
        # serializer = self.get_serializer(data=request.data)
        # serializer.is_valid(raise_exception=True)
        # self.perform_create(serializer)
        # headers = self.get_success_headers(serializer.data)
        # 序列化要调用它，只要调用serializer.data ，就会走序列化，只要走序列化，会把create返回的user对象 来使用UserRegisterSerializer类做序列化
        # 序列类中得write_only=True
        # return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        # return APIResponse(msg='注册成功') #不走序列化了，序列类中得write_only 也就不用了
        super().create(request, *args, **kwargs)

    # 写个短信登录注册接口（只需要传手机号和验证码，生成一个默认密码，以短信形式通知用户）

    # 传入手机号码和验证码（这里是验证码必须比较正确才可以），我们测试默认就是8888，然后写个随机密码，存入数据库，再给用户发个短信
    @action(methods=['GET'], detail=False)
    def sms_register(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return APIResponse(msg='注册成功')

    # 记录三次用户密码修改记录，每次改密码，不能跟之前用过的相同
    def update_password(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return APIResponse(mag='修改成功')

########################redis的使用#############################
# redis的普通链接
# import redis
# class MyRedisView(APIView):
#     def get(self,request):
#         # 访问一次，redis的a1 +1
#         conn = redis.Redis()   # 没有池的方案，来几个请求，就会创建几个链接
#         conn.incrby('a1')
#         return APIResponse()


##### 使用池
# from utils.redis_pool import POOL
# import redis
# class MyRedisView(APIView):
#     def get(self,request):
#         # 访问一次，redis的a1 +1
#         conn = redis.Redis(connection_pool=POOL)   # 没有池的方案，来几个请求，就会创建几个链接
#         conn.incrby('a1')
#         return APIResponse()

#####使用第三方
# from django_redis import get_redis_connection
#
# class MyRedisView(APIView):
#     def get(self,request):
#         # 访问一次，redis的a1 +1
#         conn = get_redis_connection()   # 从连接池中拿出一个连接
#
#         conn.incrby('a1')
#         conn.set('name','yzk')
#         return APIResponse()


#### 测试缓存的使用
# from django.core.cache import cache
#
#
# class MyRedisView(APIView):
#     def get(self, request):
#         # cache.set('age', 19, 10)  # 现在放在redis中
#         l = [1, 'lqz', [1, 3, 4, 5, 6], '彭于晏']
#         # conn = get_redis_connection()
#         # conn.lpush('l1',[1,2,3])  # 存放json格式字符串。要做序列化
#
#         cache.set('ll1', l)
#
#         return APIResponse()
#
#
# #############################################################################
#
#
# ####测试celery的使用---》前端发送一个get请求，就异步向banner表中插入一条记录
# from celery_task.home_task import add_banner
#
#
# class CeleryView(APIView):
#     def get(self, request):
#         # 同步用,不用了
#         # add_banner()
#         # 异步
#         res = add_banner.delay()
#         print(res)
#
#         return APIResponse(msg='新增banner的任务已经提交了')
#
#
# from celery_task.user_task import sckill_goods
# from celery_task.celery import app
# from celery.result import AsyncResult
#
#
# class SckillView(APIView):
#     def post(self, request, *args, **kwargs):
#         name = request.data.get('name')
#         # 提交秒杀异步任务
#         res = sckill_goods.delay(name)
#         print(res)  # 任务的id
#         return APIResponse(task_id=str(res))
#
#     def get(self, request, *args, **kwargs):
#         task_id = request.GET.get('task_id')
#         print('返回的id',task_id)
#         a = AsyncResult(id=task_id, app=app)
#         if a.successful():  # 正常执行完成
#             result = a.get()  # 任务返回的结果
#             print('判断',result)    # 返回的是True或者False
#             if result:
#                 return APIResponse(code=100, msg='秒杀成功')
#             else:
#                 return APIResponse(code=101, msg='秒杀失败')
#         elif a.status == 'STARTED':
#             print('任务已经开始被执行')
#             return APIResponse(code=103, msg='还在排队')
#         else:
#             return APIResponse(code=102, msg='没成功')


class TeamViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Team.objects.all()
    serializer_class = TeamSerializer
    throttle_classes = []
    permission_classes = []

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)



        return APIResponse(data=serializer.data)